package xuecheng.tool.codegen.mybatisplus;

import java.util.ArrayList;
import java.util.List;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.setting.Setting;
import cn.hutool.system.SystemUtil;

/**
 * mybatis-plus 代码生成
 *
 * @author PengXueCheng
 * @version 1.0.0
 **/
public class CpxCodegenMybatisPlusUtils {

    /**
     * 执行
     *
     * @param settingFilePath
     *            配置文件路径
     */
    public static void execute(String settingFilePath) {
        String projectPath = SystemUtil.getUserInfo().getCurrentDir();
        Setting setting = new Setting(settingFilePath, CharsetUtil.CHARSET_UTF_8, true);

        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 模板引擎
        AbstractTemplateEngine templateEngine = ReflectUtil.newInstance(
            setting.getStr("templateEngine", "com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine"));
        mpg.setTemplateEngine(templateEngine);

        // 全局配置
        GlobalConfig gc = getGlobalConfig(projectPath, setting);
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = getDataSourceConfig(setting);
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = getPackageConfig(setting);
        mpg.setPackageInfo(pc);

        // 自定义配置
        InjectionConfig cfg = getInjectionConfig(projectPath, pc, templateEngine);
        mpg.setCfg(cfg);

        // 配置模板
        TemplateConfig templateConfig = getTemplateConfig(setting);
        mpg.setTemplate(templateConfig);

        // 策略配置
        StrategyConfig strategy = getStrategyConfig(pc, setting);
        mpg.setStrategy(strategy);

        // 执行
        mpg.execute();
    }

    /**
     * 获取策略配置
     *
     * @param pc
     *            包配置
     * @param setting
     *            配置对象
     * @return 策略配置
     */
    private static StrategyConfig getStrategyConfig(PackageConfig pc, Setting setting) {
        String group = "StrategyConfig";
        StrategyConfig strategy = new StrategyConfig();

        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);

        strategy.setSuperEntityClass(setting.getStr("superEntityClass", group, null));
        strategy.setEntityLombokModel(setting.getBool("entityLombokModel", group, true));
        strategy.setSuperEntityColumns(StrUtil.cleanBlank(setting.getStr("superEntityColumns", group, "")).split(","));

        strategy.setRestControllerStyle(setting.getBool("restControllerStyle", group, true));
        strategy.setSuperControllerClass(setting.getStr("superControllerClass", group, null));
        strategy.setControllerMappingHyphenStyle(setting.getBool("controllerMappingHyphenStyle", group, true));

        strategy.setSuperServiceClass(setting.getStr("superServiceClass", group, null));

        strategy.setInclude(StrUtil.cleanBlank(setting.getStr("include", group, "")).split(","));

        strategy.setTablePrefix(setting.getStr("tablePrefix", group, null));
        return strategy;
    }

    /**
     * 配置自定义输出模板
     *
     * @return 自定义输出模板
     * @param setting
     *            配置对象
     */
    private static TemplateConfig getTemplateConfig(Setting setting) {
        String group = "TemplateConfig";
        TemplateConfig templateConfig = new TemplateConfig();

        // 配置自定义输出模板
        // 指定自定义模板路径，注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
        // templateConfig.setEntity("templates/entity2.java");
        // templateConfig.setService();
        // templateConfig.setController();
        templateConfig.setXml(null);
        return templateConfig;
    }

    /**
     * 获取自定义配置
     *
     * @param projectPath
     *            工程路径
     * @param pc
     *            包配置
     * @param templateEngine
     *            模板引擎
     * @return 自定义配置
     */
    private static InjectionConfig getInjectionConfig(String projectPath, PackageConfig pc,
        AbstractTemplateEngine templateEngine) {
        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };

        // // 如果模板引擎是 freemarker
        // String templatePath = "/templates/mapper.xml.ftl";
        // // 如果模板引擎是 velocity
        // // String templatePath = "/templates/mapper.xml.vm";
        String templatePath = templateEngine.templateFilePath("/templates/mapper.xml");

        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {

            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！
                return projectPath + "/src/main/resources/mapper/" + pc.getModuleName() + "/"
                    + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });

        // cfg.setFileCreate(new IFileCreate() {
        // @Override
        // public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
        // // 判断自定义文件夹是否需要创建
        // checkDir("调用默认方法创建的目录");
        // return false;
        // }
        // });

        cfg.setFileOutConfigList(focList);
        return cfg;
    }

    /**
     * 获取包配置
     *
     * @return 包配置
     * @param setting
     *            配置对象
     */
    private static PackageConfig getPackageConfig(Setting setting) {
        String group = "PackageConfig";
        PackageConfig pc = new PackageConfig();

        pc.setModuleName(setting.getStr("moduleName", group, null));
        pc.setParent(setting.getStr("parent", group, null));

        return pc;
    }

    /**
     *
     * 获取数据源配置
     *
     * @return 数据源配置
     * @param setting
     */
    private static DataSourceConfig getDataSourceConfig(Setting setting) {
        String group = "DataSourceConfig";
        DataSourceConfig dsc = setting.toBean(group, DataSourceConfig.class);

        dsc.setUrl(setting.getStr("url", group, null));
        dsc.setSchemaName(setting.getStr("schemaName", group, null));
        dsc.setDriverName(setting.getStr("driverName", group, null));
        dsc.setUsername(setting.getStr("username", group, null));
        dsc.setPassword(setting.getStr("password", group, null));

        return dsc;
    }

    /**
     * 获取全局配置
     *
     * @param projectPath
     *            工程路径
     * @param setting
     *            配置对象
     * @return 全局配置
     */
    private static GlobalConfig getGlobalConfig(String projectPath, Setting setting) {
        String group = "GlobalConfig";
        GlobalConfig gc = setting.toBean(group, GlobalConfig.class);

        gc.setOutputDir(setting.getStr("outputDir", group, StrUtil.format("{}/src/main/java", projectPath)));
        gc.setAuthor(setting.getStr("author", group, SystemUtil.getUserInfo().getName()));
        gc.setOpen(setting.getBool("open", group, true));
        gc.setSwagger2(setting.getBool("swagger2", group, true));
        gc.setDateType(DateType.SQL_PACK);

        return gc;
    }

}
